1

创建对象

1.1 通过Object对象创建

var person = new Object();
person.name = "Albert";
person.sayName = function(){
    console.log(this.name);
};

1.2 通过字面量创建

var person = {
    name : "Albert",
    sayName : function(){
        console.log(this.name)
    }
};

Object和字面量创建的问题:

创建很多对象的时候会产生大量重复代码。

1.3 工厂模式

function createPerson(name){
    var o = new Object();
    o.name = name;
    o.sayName = function(){
        console.log(this.name)
    }
    return o;
}
var person = createPerson("Albert");

工厂模式的问题:

无法识别对象类型,即无法通过instanceofconstructor来识别对象类型:

person instanceof ???;
person.constructor == ???;

1.4 构造函数

function Person(name){
    this.name = name;
    this.sayName = function(){
        console.log(this.name)
    }
}
var person = new Person("Albert");
console.log(person.constructor == Person)//true
console.log(person instanceof Person)//true

构造函数的问题:

每个方法都要在每个实例上重新创建一次,尤其是函数,这样每个Person的实例都包含了一个不同的sayName的函数实例。

注意1
构造函数没有return语句。要创建Person的新实例,必须采用new操作符,new操作符大体上完成了一下4件事情:

  • 创建一个新的对象(本例中Person创建的新对象,记为person);

  • 将构造函数的作用域赋给新对象(this=>person);

  • 执行构造函数中的代码(Person中的this.name=name;this.say.....);

  • 返回新对象

注意2
构造函数也是函数,如果不通过new操作符调用,则作用环境为全局(浏览器中为windows,node环境中为global

function Person(name){
    this.name = name;
    this.sayName = function(){
        console.log(this.name)
    }
}

Person("BB");
global.sayName()//BB
console.log(global.name)//BB

1.5 原型模式

function Person(name){}
Person.prototype.name = "Albert";
Person.prototype.sayName = function(){
        console.log(this.name)
    }

var person = new Person();
console.log(Object.getPrototypeOf(person)==Person.prototype);//true

浏览器支持:IE9+,这样所有的Person实例共享name属性及sayName函数

注意1

  • 对象的某个属性是否来自实例,可通过hasOwnProperty()来确定,如果是在原型中,则返回false

  • 判断对象是否具备属性,可以通过in操作符,例如console.log("name" in person)//true来判断,不论是在原型还是实例中,都返回true,通过for-in循环时,实例及原型中均会被枚举。

注意2
在定义原型时,如果用字面量代替为prototype属性定义,则原型的constructor属性不会指向Person。因为通过字面量定义,完全重写了默认的prototype对象。但是此时instanceof还是能够返回正确的结果。

function Person(name){};
Person.prototype={
    name : "Albert",
    sayName : function(){
        console.log(this.name);
    }
};
var person = new Person();
console.log(person instanceof Person);//true
console.log(person.constructor == Person);//false
console.log(person.constructor == Object);//true

所以可以再补充定义:

Object.defineProperty(Person.prototype,"constructor",{
    enumerable:false,
    value:Person
})

注意3
在重定义原型前,不能创建对象实例,否则会造成实例的原型指向错误

function Person(name){};
var person = new Person();
Person.prototype={
    name : "Albert",
    sayName : function(){
        console.log(this.name);
    }
};
person.sayName(); //error

此例中person的原型被指向了Person的默认原型,固调用sayName函数会发生错误。

原型模式的问题:

  • 小问题:为了省略构造函数传递初始化参数,所有的实例在默认情况下都会去的想通的属性值

  • 原型属性被所有实例共享(适合function类型的值),而通常情况下,引用类型(ArrayObject)属性值一般不希望对所有实例共享。

1.6 构造函数与原型组合

利用构造函数都是实例属性和原型的共享特性,分别定义对应的内容,组合共同完成对象创建,而且该模式还支持想构造函数传递参数。

function Person(name){
    this.name = name;
    this.friends = ["Bob","Harry"];//引用类型为实例属性
};
Person.prototype.sayName = function(){
        console.log(this.name);
};

1.7 动态原型模式

将1.6中的组合封装在一个构造函数中的模式。具体方法为:检查某个应该存在的方法是否有效来决定是否需要初始化原型。

function Person(name){
    this.name = name;
    this.friends = ["Bob","Harry"];//引用类型为实例属性
    //****ProtoType****
    if(typeof this.sayName != "function"){
        Person.prototype.sayName = function(){
            console.log(this.name);
        };
    }
};

1.8 寄生构造模式

构造函数在不反回值的情况下,默认会返回新对象实例。
而通过在函数末尾添加return语句,可以重写new后调用函数时的返回值。

function Person(name){
    var o = new Object();
    o.name = name;
    o.sayName = function(){
        console.log(this.name);
    };
    return o;
};
var person = new Person("Albert");
console.log(person instanceof Person);//false

该函数除了使用new操作符和把包装函数取名叫“构造函数”以外,和工厂模式其实是一模一样的。
该模式属于比较特殊的构造模式,可用于不允许修改原对象的情况。

function SpecialArray(){
    var values = new Array();
    values.push.apply(values,arguments);
    values.toPipedString = function(){
        return this.join("|");
    };
    return values
}

1.9 稳妥(durable)构造函数模式

该模式构造出来的对象没有公共属性,不适用this对象,不适用new操作符,适用于在一些安全环境中,可防止数据被其它应用(如Mashup)改动(利用闭包特性),类似于寄生构造函数模式,单不适用thisnew

function Person(name){
    var o = new Object();
    //****定义私有变量和函数****
    var _name = name;
    o.sayName = function(){
        console.log(_name);
    };    
    return o;
};
var person = Person("Albert");

这种模式中,除了sayName()方法以外,没有其它办法访问_name的值。


abc126
19 声望0 粉丝